/*
 * PVPRewardResource.cpp
 *
 *  Created on: 2013. 9. 13.
 *      Author: mega@gamevil.com
 */

#include "../User.h"
#include "../engine.h"
#include "../NUtil/Utils.h"
#include "../NResource/Static.h"
#include "PVPRewardResource.h"

//#include "../NLogic/Level.h"

namespace ProjectZ { namespace NResource {

PVPRewardResource::PVPRewardResource()
{
	pPVPRewardAD	= new PVPRewardData;
	pPVPRewardIOS	= new PVPRewardData;
}

PVPRewardResource::~PVPRewardResource()
{
	delete pPVPRewardAD;
	delete pPVPRewardIOS;
}

bool PVPRewardResource::LoadResource()
{
	if (false == pPVPRewardAD->LoadResource(MARKET_GOOGLE, SC_KAKAO_GOOGLE))
		return false;

	if (false == pPVPRewardIOS->LoadResource(MARKET_IOS, SC_KAKAO_IOS))
		return false;

	return true;
}

PVPRewardData::FlyweightRate * PVPRewardResource::GetFly(int company, int saleCode, PVPRewardData::Key & clsKey)
{
	NUtil::MarketType marketType = NUtil::GetMarketType(company, saleCode);

	switch (marketType)
	{
	case NUtil::MarketType::AD_KAKAO:
		return pPVPRewardAD->GetFly(clsKey);

	case NUtil::MarketType::IOS_KAKAO:
		return pPVPRewardIOS->GetFly(clsKey);

	default:
		return NULL;
	}

	return NULL;
}

PVPRewardData::FlyweightItem * PVPRewardResource::GetFly(int company, int saleCode, int level)
{
	NUtil::MarketType marketType = NUtil::GetMarketType(company, saleCode);

	switch (marketType)
	{
	case NUtil::MarketType::AD_KAKAO:
		return pPVPRewardAD->GetFly(level);

	case NUtil::MarketType::IOS_KAKAO:
		return pPVPRewardIOS->GetFly(level);

	default:
		return NULL;
	}

	return NULL;
}

PVPRewardData::~PVPRewardData()
{
	std::for_each(clsFlyRateTree.begin(), clsFlyRateTree.end(), ProjectZ::NUtil::del_second_ptr<PVPREWARDRATETREE::value_type>);
	std::for_each(clsFlyItemTree.begin(), clsFlyItemTree.end(), ProjectZ::NUtil::del_second_ptr<PVPREWARDITEMTREE::value_type>);
}

void
PVPRewardData::ClearRateTree()
{
	std::for_each(clsFlyRateTree.begin(), clsFlyRateTree.end(), ProjectZ::NUtil::del_second_ptr<PVPREWARDRATETREE::value_type>);
	clsFlyRateTree.clear();
}

void
PVPRewardData::ClearItemTree()
{
	std::for_each(clsFlyItemTree.begin(), clsFlyItemTree.end(), ProjectZ::NUtil::del_second_ptr<PVPREWARDITEMTREE::value_type>);
	clsFlyItemTree.clear();
}

bool PVPRewardData::LoadResource(int company, int saleCode)
{
	::Database::Command::Auto clsAuto(::Database::GETCOMMANDPOOL());
	clsAuto->SetQueryType(::Database::Command::SELECT);

	// PVP 보상 아이템 확률 조회
	clsAuto->MakeQuery("SELECT NATIONAL_CODE, type, sub_type, value1, value2 FROM resource_pvp_reward_rate WHERE company=%d AND sale_cd=%d ORDER BY type, sub_type", company, saleCode);

	if (false == ::Database::GETSESSION()->SyncExecute(1, clsAuto))
		return false;

	if( clsAuto->GetErrorIdx() != 0 )
		return false;

	if (0 == clsAuto->ResultRowCount())
		return false;

	ClearRateTree();

	while( clsAuto->Next() )
	{
		::Toolkit::Str<3> NATIONAL_CODE;
		PVPRewardData::FlyweightRate * pFly = new PVPRewardData::FlyweightRate;

		clsAuto->GetRecord() >> NATIONAL_CODE >> pFly->_TYPE >> pFly->_SUB_TYPE >> pFly->_VALUE1 >> pFly->_VALUE2;

		if (0 != Config::Instance().GetResourceDatabase()._strNational.compare(NATIONAL_CODE.c_str()))
		{
			DEBUGLOG("%s:%d NATIONAL_CODE ERROR!!! Config National Code [%s] , Resource National Code [%s]",
					__FILE__, __LINE__,
					Config::Instance().GetResourceDatabase()._strNational.c_str(),
					NATIONAL_CODE.c_str());
			return false;
		}

		clsFlyRateTree[PVPRewardData::Key(pFly->_TYPE, pFly->_SUB_TYPE)] = pFly;
	}

	clsAuto->Finalize();

	// 레벨대 별 아이템 TID 정보 조회
	clsAuto->MakeQuery("SELECT * FROM resource_pvp_reward WHERE company=%d AND sale_cd=%d", company, saleCode);

	if (false == ::Database::GETSESSION()->SyncExecute(1, clsAuto))
		return false;

	if( clsAuto->GetErrorIdx() != 0 )
		return false;

	if (0 == clsAuto->ResultRowCount())
		return false;

	ClearItemTree();

	while( clsAuto->Next() )
	{
		int seq;
		int tmp_company;
		int tmp_salecode;

		Toolkit::Str<3> NATIONAL_CODE;

		PVPRewardData::FlyweightItem * pFly = new PVPRewardData::FlyweightItem;

		clsAuto->GetRecord() >> NATIONAL_CODE >> seq >> tmp_company >> tmp_salecode >> pFly->_MIN_LEVEL >> pFly->_MAX_LEVEL
				>> pFly->_WEAPONE >> pFly->_HELMET >> pFly->_ARMOR >> pFly->_GLOVES
				>> pFly->_SHOES >> pFly->_NECKLACE >> pFly->_CLOAK >> pFly->_RING >> pFly->_CHARM;

		if (0 != Config::Instance().GetResourceDatabase()._strNational.compare(NATIONAL_CODE.c_str()))
		{
			DEBUGLOG("%s:%d NATIONAL_CODE ERROR!!! Config National Code [%s] , Resource National Code [%s]",
					__FILE__, __LINE__,
					Config::Instance().GetResourceDatabase()._strNational.c_str(),
					NATIONAL_CODE.c_str());
			return false;
		}

		clsFlyItemTree[pFly->_MIN_LEVEL] = pFly;
	}

	return true;
}

PVPRewardData::FlyweightRate * PVPRewardData::GetFly(PVPRewardData::Key & clsKey)
{
	auto iter = clsFlyRateTree.find(clsKey);

	if (iter == clsFlyRateTree.end())
		return NULL;

	return iter->second;
}

PVPRewardData::FlyweightItem * PVPRewardData::GetFly(int level)
{
	int levelRange = 1;

	if (level >= 10)
		levelRange = (level / 10) * 10;

	auto iter = clsFlyItemTree.find(levelRange);

	if (iter == clsFlyItemTree.end())
		return NULL;

	return iter->second;
}



PVPRewardData::FlyweightRate * PVPRewardResource::GetFlyFromType(PVPRewardData::PVPREWARDRATETREE & clsRateTree, int type)
{
	int accRate = 0;
	int randRate = rand() % 100;

	auto iter = clsRateTree.begin();

	for ( ; iter != clsRateTree.end(); iter++)
	{
		if (iter->first.type != type)
			continue;

		accRate += iter->second->_VALUE1;

		if (randRate < accRate)
			break;
	}

	return iter->second;
}


int PVPRewardResource::GetClassType()
{
	//------------------------------------------------------
	// Changed by spencer(2014.07.02)
	// 성기사 클래스 추가 open/close에 따른 처리
	//------------------------------------------------------
	int iClassCount = EnumCharClass::CLASS_TYPE_MAX;
	if ( false == NResource::Static::Instance().GetContentsOpenResource()->IsOpen(ContentsOpen::NEW_CLASS_PALADIN) )
		iClassCount -= 1;

	return rand() % iClassCount; //EnumCharClass::CLASS_TYPE_MAX;
}

int PVPRewardResource::GetItemTid(PVPRewardData * pPVPReward, int level, int sheet)
{
	PVPRewardData::FlyweightItem * pFly = pPVPReward->GetFly(level);

	switch (sheet)
	{
	case EnumClassItemTableType::CLASS_ITEM_TABLE_WEAPONE:	return pFly->_WEAPONE;
	case EnumClassItemTableType::CLASS_ITEM_TABLE_HELMET:	return pFly->_HELMET;
	case EnumClassItemTableType::CLASS_ITEM_TABLE_ARMOR:	return pFly->_ARMOR;
	case EnumClassItemTableType::CLASS_ITEM_TABLE_GLOVES:	return pFly->_GLOVES;
	case EnumClassItemTableType::CLASS_ITEM_TABLE_SHOES:	return pFly->_SHOES;
	case EnumClassItemTableType::CLASS_ITEM_TABLE_NECKLACE:	return pFly->_NECKLACE;
	case EnumClassItemTableType::CLASS_ITEM_TABLE_CLOAK:	return pFly->_CLOAK;
	case EnumClassItemTableType::CLASS_ITEM_TABLE_RING:		return pFly->_RING;
	case EnumClassItemTableType::CLASS_ITEM_TABLE_CHARM:	return pFly->_CHARM;
	}

	return 0;
}

int PVPRewardResource::GetItemSheet(int minType, int maxType)
{
	return NUtil::GetRandBetween(minType, maxType);
}

int PVPRewardResource::GetEtcItemTid(PVPRewardData * pPVPReward)
{
	PVPRewardData::Key clsKey(6, 0);
	PVPRewardData::FlyweightRate * pFlyRate = pPVPReward->GetFly(clsKey);

	int minTid = pFlyRate->_VALUE1;
	int maxTid = pFlyRate->_VALUE2;

	return NUtil::GetRandBetween(minTid, maxTid);
}

int PVPRewardResource::AddEffect(PVPRewardData * pPVPReward, int effectValue)
{
	PVPRewardData::Key clsKey(5, 0);
	PVPRewardData::FlyweightRate * pFlyRate = pPVPReward->GetFly(clsKey);

	int retValue = effectValue;

	int rate = pFlyRate->_VALUE1;
	int randRate = rand() % 100;

	if (randRate < rate)
	{
		int addPercent = NUtil::GetRandBetween(1, rate);
		retValue = NUtil::AddPercentage(retValue, addPercent);
	}

	return retValue;
}


int PVPRewardResource::GetItemLevelDown(PVPRewardData * pPVPReward, int level)
{
	/*/
	 * 아이템 레벨이 낮아질 확률을 계산해서 최종 아이템 레벨을 결정한다.
	 */
	PVPRewardData::Key clsKey(4, 0);
	PVPRewardData::FlyweightRate * pFlyRate = pPVPReward->GetFly(clsKey);

	int itemLevel = level;
	int rate = pFlyRate->_VALUE1;
	int randRate = rand() % 100;

	if (randRate < rate)
	{
		int minus = NUtil::GetRandBetween(1, rate);
		itemLevel -= minus;
	}

	if (itemLevel < 0)
		itemLevel = 1;

	return itemLevel;
}

void PVPRewardResource::PVPReward(User * pUser, NLogic::Item::Data & clsData)
{
	PVPRewardData * pPVPReward = NULL;

	NUtil::MarketType marketType = NUtil::GetMarketType(pUser->GetUserInfo().company, pUser->GetUserInfo().sale_code);

	switch (marketType)
	{
	case NUtil::MarketType::AD_KAKAO:
		pPVPReward = pPVPRewardAD;
		break;

	case NUtil::MarketType::IOS_KAKAO:
		pPVPReward = pPVPRewardIOS;
		break;

	default:
		pPVPReward = NULL;
	}

	if (pPVPReward == NULL)
		return;

	PVPRewardData::PVPREWARDRATETREE & clsRateTree = pPVPReward->GetRateTree();
	PVPRewardData::FlyweightRate * pFlyRate = NULL;

	// PVP 보상 여부 결정
	PVPRewardData::Key clsKey(1, 0);
	pFlyRate = pPVPReward->GetFly(clsKey);

	int rewardRate	= pFlyRate->_VALUE1;
	int randRate	= rand() % 100;

	if (randRate > rewardRate)
	{
		// 보상이 없음을 확인하기 위해 bag_type 필드 이용
		clsData.bag_type = -1;
		return;
	}

	pFlyRate = this->GetFlyFromType(clsRateTree, 2);
	int rewardType = pFlyRate->_SUB_TYPE;

	switch (rewardType)
	{
	case 0:	// 무기 보상
		clsData.class_type	= this->GetClassType();
		clsData.sub_type	= EnumClassItemTableType::CLASS_ITEM_TABLE_WEAPONE;
		clsData.tid			= this->GetItemTid(pPVPReward, pUser->GetCharacterInfo().level, clsData.sub_type);

		// 등급 결정
		pFlyRate = this->GetFlyFromType(clsRateTree, 3);
		clsData.quality		= pFlyRate->_SUB_TYPE;
		break;

	case 1:	// 방어구 보상
		clsData.class_type	= this->GetClassType();
		clsData.sub_type	= this->GetItemSheet(EnumClassItemTableType::CLASS_ITEM_TABLE_HELMET, EnumClassItemTableType::CLASS_ITEM_TABLE_SHOES);
		clsData.tid			= this->GetItemTid(pPVPReward, pUser->GetCharacterInfo().level, clsData.sub_type);

		// 등급 결정
		pFlyRate = this->GetFlyFromType(clsRateTree, 3);
		clsData.quality		= pFlyRate->_SUB_TYPE;
		break;

	case 2:	// 장신구 보상
		clsData.class_type	= -1;
		clsData.sub_type	= this->GetItemSheet(EnumClassItemTableType::CLASS_ITEM_TABLE_NECKLACE, EnumClassItemTableType::CLASS_ITEM_TABLE_CHARM);
		clsData.tid			= this->GetItemTid(pPVPReward, pUser->GetCharacterInfo().level, clsData.sub_type);

		// 등급 결정
		pFlyRate = this->GetFlyFromType(clsRateTree, 3);
		clsData.quality		= pFlyRate->_SUB_TYPE;
		break;

	case 3:	// 기타 아이템 보상
		clsData.class_type	= -1;
		clsData.sub_type	= EnumClassItemTableType::CLASS_ITEM_TABLE_ETC;
		clsData.tid			= this->GetEtcItemTid(pPVPReward);
		clsData.quality		= -1;
		break;
	}

	NResource::ItemResource * pItemResource = NResource::Static::InstancePtr()->GetItemResource();

	clsData.quantity		= 1;
	clsData.bag_type		= pItemResource->GetItemBagType(clsData);
	clsData.cur_duration	= pItemResource->GetItemDurability(clsData);
	clsData.max_duration	= clsData.cur_duration;

	int itemLevel			= pItemResource->GetItemLevel(clsData);
	clsData.level			= this->GetItemLevelDown(pPVPReward, itemLevel);

	// 아이템 기본 효과 설정
	pItemResource->setItemEffect(clsData);

	// 기본 효과에 추가 능력치 적용
	clsData.eff_value[0]	= this->AddEffect(pPVPReward, clsData.eff_value[0]);
}

} /* NResource */ } /* ProjectZ */
